import time
from pathlib import Path

import requests
from bs4 import BeautifulSoup
import pandas as pd
from ppadb.client import Client as AdbClient
from openpyxl import load_workbook
from openpyxl.styles import PatternFill, Font
from datetime import datetime

CONF_FILE = 'conf/app_info.csv'
DATA_FILE = 'data/result.xlsx'
data_filepath = Path(DATA_FILE)
CHECKED_FILE = str(data_filepath.parent / f'{data_filepath.stem}_checked{data_filepath.suffix}')
FORMATTED_FILE = str(data_filepath.parent / f'{data_filepath.stem}_formatted{data_filepath.suffix}')


def crawl_apkpure(app_type: str, apkpure_alias: str, pkg_id: str):
    """
    爬取apkpure网站的版本和发布日期信息
    :param app_type:
    :param apkpure_alias:
    :param pkg_id:
    :return:
    """

    if app_type == 'android':
        url = f"https://apkpure.net/cn/{apkpure_alias}/{pkg_id}"
        version_selector = 'p.details_sdk > span'
        release_date_selector = 'p.date'
        date_format = '%Y年%m月%d日'
    elif app_type == 'ios':
        url = f"https://iphone.apkpure.net/app/{apkpure_alias}/{pkg_id}"
        version_selector = 'span.app-version-number'
        release_date_selector = 'div.app-info-list > div:nth-child(4) > div.app-info-title'
        date_format = '%b %d, %Y'
    else:
        return

    agent = {
        'User-Agent': 'Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; '
                      'Acoo Browser 1.98.744; .NET CLR 3.5.30729)'
    }

    version, released_date_str = '', ''
    try:
        # 发送请求
        response = requests.get(url, headers=agent)

        # 解析网页
        soup = BeautifulSoup(response.content, 'html.parser')

        version = soup.select_one(version_selector).text.strip()
        released = soup.select_one(release_date_selector).text
        released_date = datetime.strptime(released, date_format)
        released_date_str = datetime.strftime(released_date, '%Y/%m/%d', )

    except Exception as e:
        print(e)
    finally:
        pass

    return version, released_date_str


def get_apkpure_versions():
    """
    获取apkpure上的版本
    :return:
    """

    # 加载配置
    df = pd.read_csv(CONF_FILE, encoding='utf-8')

    # 遍历dataframe
    for idx, row in df.iterrows():
        print(f'Fetching data for {row["apkpure_alias"]}...')

        # 获取apkpure网站的版本
        version, rel_date_str = crawl_apkpure(row['platform'].lower(), row['apkpure_alias'], row['pkg_id'])

        # 更新dataframe
        df.loc[idx, 'apkpure_version'] = f'V{version}'
        df.loc[idx, 'apkpure_date'] = rel_date_str

        print(version, rel_date_str)

    # 将DataFrame写入Excel文件
    with pd.ExcelWriter(DATA_FILE) as writer:
        df.to_excel(writer, index=False)


def get_installed_versions():
    """
    获取设备上已安装的版本
    :return:
    """

    # 加载表
    df = pd.read_excel(DATA_FILE)

    # 遍历dataframe
    for idx, row in df.iterrows():
        print(f'Fetching installed version...')

        # 获取安卓手机安装版本
        inst_version, auth = get_android_installed_version(row['pkg_id'])

        # 更新dataframe
        df.loc[idx, f'{auth}_version'] = f'V{inst_version}'

    # 将DataFrame写入Excel文件
    with pd.ExcelWriter(DATA_FILE) as writer:
        df.to_excel(writer, index=False)


def get_android_installed_version(package_name: str):
    """
    获取安卓设备已安装版本
    :param package_name:
    :return:
    """

    version, brand, model = '', '', ''
    auth = ''

    # 默认的 ADB 主机和端口
    adb_host = "127.0.0.1"
    adb_port = 5037

    # 连接到 ADB 服务器
    client = AdbClient(host=adb_host, port=adb_port)

    # 获取已连接的设备列表
    devices = client.devices()


    if len(devices) == 0:
        print("没有设备连接")
    else:
        device = devices[0]  # 假设我们只关心第一个连接的设备

        try:
            # brand = devices[0].shell(f"getprop ro.product.brand")
            # model = devices[0].shell(f"getprop ro.product.model")

            su = devices[0].shell(f"su -c id")
            if 'uid=0(root)' in su:
                auth = 'bypassed'
            else:
                auth = 'default'

            # 获取包的路径
            path = device.shell(f"pm path {package_name}")
            # 如果路径为空，应用可能没有安装
            if path:
                # 获取版本号
                version = device.shell(f"dumpsys package {package_name} | grep versionName")
                version = version.split('=')[1].strip().splitlines()[0]
                print(f"Package: {package_name}, Version: {version}")
            else:
                print(f"Package: {package_name} not installed.")
        except Exception as e:
            print(f"Error retrieving version for package {package_name}: {e}")

    return version, auth


def get_ios_installed_version(package_name):
    """
    获取iOS设备已安装版本
    :param package_name:
    :return:
    """
    # 目前没有合适的自动化方案，手动3Utools可以
    pass


def compare_versions(version1: str, version2: str):
    """
    比较版本号
    :param version1:
    :param version2:
    :return: -1 表示小于，0 表示相等，1表示大于
    """
    flag = 0

    if version1 and not version2:
        flag = 1
        return flag
    if version2 and not version1:
        flag = -1
        return flag

    # 移除版本号前的 'V' 或 'v'（如果存在）
    v1 = version1.lower().replace('V', '')
    v2 = version2.lower().replace('V', '')

    # 将版本号分割为数字列表
    num_list1 = v1.split('.')
    num_list2 = v2.split('.')

    # 比较版本号的每一部分
    for n1, n2 in zip(num_list1, num_list2):
        if not n1.isdigit() or not n2.isdigit():
            continue

        if int(n1) > int(n2):
            flag = 1
            return flag
        elif int(n1) < int(n2):
            flag = -1
            return flag

    return flag


def check_version():
    """
    检查手机安装版本是否低于apkpure版本，若是则将单元格黄色高亮。
    避免漏更新。
    :return:
    """

    book = load_workbook(DATA_FILE)
    sheet = book.active
    first_row = [cell.value for cell in sheet[1]]

    yellow = PatternFill(start_color='FFFF00', end_color='FFFF00', fill_type='solid')
    red = PatternFill(start_color='FF0000', end_color='FF0000', fill_type='solid')
    no_fill = PatternFill(fill_type=None)

    # 遍历每一行
    for row in range(2, sheet.max_row + 1):
        platform_cell = sheet.cell(row=row, column=first_row.index('platform') + 1)
        app_name_cell = sheet.cell(row=row, column=first_row.index('app') + 1)
        apkpure_version_cell = sheet.cell(row=row, column=first_row.index('apkpure_version') + 1)
        bypassed_version_cell = sheet.cell(row=row, column=first_row.index('bypassed_version') + 1)
        default_version_cell = sheet.cell(row=row, column=first_row.index('default_version') + 1)

        # 逻辑1：需求原本不支持的app，对app列单元格高亮。
        # 如果只是非提权不支持，黄色高亮；如果提权&非提权都不支持，则红色高亮。
        if platform_cell.value == 'Android':

            #
            if app_name_cell.value in ['letstalk', 'signal']:
                app_name_cell.fill = red
                bypassed_version_cell.value = default_version_cell.value = None

            if app_name_cell.value in ['whatsapp', 'whatsapp-business', 'instagram', 'gmail']:
                app_name_cell.fill = yellow
                default_version_cell.value = None
                default_version_cell.fill = no_fill

        if platform_cell.value == 'iOS':

            if app_name_cell.value in ['telegram', 'facebook', 'firefox', 'whatsapp-business', 'skype', 'letstalk',
                                       'messenger', 'signal', 'gmail', 'instagram']:
                app_name_cell.fill = yellow
                default_version_cell.value = None
                default_version_cell.fill = no_fill

        # 逻辑2：如果apkpure的版本与实际安装版本不一致，则高亮apkpure_version
        if apkpure_version_cell.value not in [bypassed_version_cell.value, default_version_cell.value]:
            apkpure_version_cell.fill = yellow

        # 提醒逻辑3：如果apkpure的版本与实际安装版本不一致，则高亮apkpure_version
        if default_version_cell.value and bypassed_version_cell.value:
            if default_version_cell.value != bypassed_version_cell.value:
                bypassed_version_cell.fill = default_version_cell.fill = red

    # 保存修改后的Excel工作簿
    file_path = Path(DATA_FILE)
    book.save(file_path.parent / f'{file_path.stem}_checked{file_path.suffix}')

    book.close()


def reformat():
    """
    按照MY格式
    :return:
    """

    df = pd.read_excel(CHECKED_FILE)
    df = df.map(lambda x: None if pd.isna(x) else x)

    # 设定app排列顺序
    order = df[df['platform'] == 'Android']['app'].to_list()
    # 设定平台排列顺序
    platform_order = ['iOS-bypassed', 'iOS-default', 'Android-bypassed', 'Android-default']

    records = df.to_dict('records')

    # 将bypassed_version和default_version两列变成两行
    cp_list = []
    for rec in records:
        rec_cp = rec.copy()
        rec_cp.update({'version': rec_cp['default_version'], 'platform': f'{rec_cp["platform"]}-default'})
        rec_cp.pop('bypassed_version')
        rec_cp.pop('default_version')

        rec.update({'version': rec['bypassed_version'], 'platform': f'{rec["platform"]}-bypassed'})
        rec.pop('bypassed_version')
        rec.pop('default_version')

        cp_list.append(rec_cp)

    all_list = []
    for i in range(len(records)):
        all_list.append(records[i])
        all_list.append(cp_list[i])

    big_df = pd.DataFrame(data=all_list)
    big_df.drop(['apkpure_alias', 'pkg_id', 'apkpure_version'], axis=1, inplace=True)

    # 指定列的呈现顺序
    big_df = big_df[['app', 'platform', 'version', 'apkpure_date']]

    # 指定排序，规则 app>platform
    big_df['app'] = pd.Categorical(big_df['app'], categories=order, ordered=True)
    big_df['platform'] = pd.Categorical(big_df['platform'], categories=platform_order, ordered=True)
    big_df = big_df.sort_values(by=['app', 'platform'])

    # 保存到本地
    with pd.ExcelWriter(FORMATTED_FILE) as writer:
        big_df.to_excel(writer, index=False)

    print(f'成功写入到 {FORMATTED_FILE}')

def op_chain():
    op_list = [get_apkpure_versions,
               get_installed_versions,
               check_version,
               reformat]

    for op in op_list:
        try:
            op()
        except Exception as e:
            print(f'Errors occurred when handling {op.__name__}: {e}')

        print('Done')


if __name__ == '__main__':
    # get_apkpure_versions()
    # get_installed_versions()
    # check_version()
    reformat()


